﻿#pragma once

#include "config/box_config.hh"

namespace kratos {
namespace service {
class ServiceBox;
}
} // namespace kratos

namespace kratos {
namespace config {

#define DECLARE_FUNCTION(name)                                                 \
  kconfig::AttributePtr name(const std::vector<kconfig::AttributePtr> &args);

#define IMPL_FUNCTION(name)                                                    \
  kconfig::AttributePtr BoxConfigImpl::name(                                   \
      const std::vector<kconfig::AttributePtr> &args)

#define REG_FUNCTION(name)                                                     \
  config_->register_function(                                                  \
      #name, std::bind(&BoxConfigImpl::name, this, std::placeholders::_1))

#define REG_ATTRIBUTE(name, value)                                             \
  config_->get_root_domain()->addAttribute(#name, value);

/**
 * ServiceBox配置器.
 */
class BoxConfigImpl : public BoxConfig {
  using StringList = std::vector<std::string>;
  using StringMap = std::unordered_map<std::string, std::string>;
  using ReloadListenerMap = std::unordered_map<std::string, ReloadListener>;

  std::string logger_config_line_{
      "console://;line=[%y%m%d-%H:%M:%S:%U];flush=true"}; ///< 默认日志配置

  service::ServiceBox *box_{nullptr};     ///< 服务容器
  std::string config_file_path_;          ///< 配置文件路径
  StringList listener_list_;              ///< 监听器列表
  std::string listener_host_type_{"tcp"}; ///< listener.host网络类型
  std::string finder_type_{"zookeeper"};  ///< 服务发现类型
  std::string finder_hosts_;              ///< 服务发现远程主机
  std::time_t service_finder_connect_timeout_{5000}; ///< 服务发现连接超时
  StringList necessary_service_;        ///< 容器所依赖的必需服务
  int connect_other_box_timeout_{5000}; ///< 连接其他容器超时
  std::unique_ptr<kconfig::Config> config_{nullptr}; ///< 内部配置组件
  int box_channel_recv_buffer_len_{1024 * 16}; ///< 容器管道读缓冲长度
  std::string box_name_{"box"};        ///< 容器名称，影响PID文件名
  std::string service_dir_{"service"}; ///< 本地服务的存储目录
  bool is_auto_load_service_{false}; ///< 是否自动加载服务，忽略preload_service
  StringMap service_map_;            ///< 需要加载的本地服务名
  bool is_open_coroutine_{true}; ///< 是否对本地服务的调用开启协程
  ReloadListenerMap reload_listener_map_;       ///< 配置重载监听器
  std::string remote_service_repo_version_api_; ///< 远程服务仓库版本API
  std::string
      remote_service_repo_latest_version_api_; ///< 远程服务仓库最新版本API
  std::string remote_service_repo_dir_; ///< 远程服务仓库下载路径
  bool is_open_remote_update_{false};   ///< 是否开启远程更新
  int remote_repo_check_interval_{60};  ///< 远程仓库检查周期,秒
  bool is_start_as_daemon_{false};      ///< 是否以守护进程方式启动
  int http_max_call_timeout_{5};        ///< HTTP调用最大超时时间,秒
  bool is_open_rpc_stat_{false};        ///< 是否开启RPC统计
  bool is_open_trace_{false};           ///< 是否开启链路跟踪
  std::string module_dir_;              ///< 模块存放路径
  bool is_open_limit_{false};           ///< 限流开关
  LimitConfigVector limit_config_vec_;  ///< 限流配置
  std::string version_; ///< 用户配置的版本号, 用于在服务发现中区分版本号
  bool is_open_rpc_timeout_{true}; ///< RPC超时开关
  bool is_lock_config_{true};      ///< 是否锁定配置

public:
  /**
   * 构造.
   *
   */
  BoxConfigImpl(kratos::service::ServiceBox *box);
  /**
   * 析构.
   *
   */
  virtual ~BoxConfigImpl();
  /**
   * 加载配置.
   * @param config_file_path 配置文件路径
   * @param [OUT] error 错误
   * @retval true 成功
   * @retval false 失败
   */
  auto load(const std::string &config_file_path, std::string &error) -> bool;
  /**
   * 重新加载配置.
   * @param config_file_path 配置文件路径
   * @param [OUT] error 错误
   * @retval true 成功
   * @retval false 失败
   */
  auto reload(const std::string &config_file_path, std::string &error) -> bool;
  /**
   * 设置一个监听回调，监听配置重载事件
   *
   * \param name 监听器名称
   * \param listener 监听回调
   * \retval true 成功
   * \return false 失败
   */
  virtual auto add_reload_listener(const std::string &name,
                                   ReloadListener listener) -> bool override;
  /**
   * 删除新加载事件监听器.
   *
   * \param name 监听器名称
   * \retval true 成功
   * \return false 失败
   */
  virtual auto remove_reload_listener(const std::string &name) -> bool override;
  /**
   * 获取配置器指针，用于获取自定义配置.
   *
   * \return 配置器指针
   */
  virtual auto get_config_ptr() -> kconfig::Config * override;
  /**
   * \brief 取得网络监听器列表, 例如:"127.0.0.1:12345"
   * \return 网络监听器列表
   */
  virtual auto get_listener_list() const
      -> const std::vector<std::string> & override;
  /**
   * 获取服务发现节点类型.
   *
   * \return 服务发现节点类型
   */
  virtual auto get_service_finder_type() const -> const std::string & override;
  /**
   * 获取服务发现主机地址列表.
   *
   * \return 服务发现主机地址列表
   */
  virtual auto get_service_finder_hosts() const -> const std::string & override;
  /**
   * 获取服务发现节点连接超时，毫秒.
   *
   * \return 服务发现节点连接超时，毫秒
   */
  virtual auto get_service_finder_connect_timeout() const
      -> std::time_t override;
  /**
   * 设置服务发现节点连接超时，毫秒.
   *
   * \param timeout 服务发现节点连接超时，毫秒
   */
  auto set_service_finder_connect_timeout(std::time_t timeout) const -> void;
  /**
   * 获取必须的服务名列表.
   *
   * \return 必须的服务名列表
   */
  virtual auto get_necessary_service() const
      -> const std::vector<std::string> & override;
  /**
   * 获取连接其他服务容器超时，秒.
   *
   * \return 连接其他服务容器超时，秒.
   */
  virtual auto get_connect_other_box_timeout() const -> int override;
  /**
   * 获取管道接收缓冲区长度，字节.
   *
   * \return 管道接收缓冲区长度，字节.
   */
  virtual auto get_box_channel_recv_buffer_len() const -> int override;
  /**
   * 获取服务容器名.
   *
   * \return 服务容器名.
   */
  virtual auto get_box_name() const -> const std::string & override;
  /**
   * 获取日志配置.
   *
   * \return 日志配置.
   */
  virtual auto get_logger_config_line() const -> const std::string & override;
  /**
   * 获取本地服务目录.
   *
   * \return 本地服务目录.
   */
  virtual auto get_service_dir() const -> const std::string & override;
  /**
   * 获取需要加载的本地服务表,{UUID,服务名}.
   *
   * \return 本地服务表,{UUID,服务名}.
   */
  virtual auto get_preload_service() const
      -> const std::unordered_map<std::string, std::string> & override;
  /**
   * 是否开启协程.
   *
   * \return true或者false
   */
  virtual auto is_open_coroutine() const -> bool override;
  /**
   * 是否锁定配置.
   *
   * \return true是,false否
   */
  virtual auto is_lock_config() -> bool override;
  /**
   * 获取远程组件仓库版本文件API.
   *
   * \return 远程组件仓库版本文件API.
   */
  virtual auto get_remote_service_repo_version_api() const
      -> const std::string & override;
  /**
   * 获取远程仓库API.
   *
   * \return 远程仓库API.
   */
  virtual auto get_remote_service_repo_dir() const
      -> const std::string & override;
  /**
   * 获取远程组件仓库最新版本文件API.
   *
   * \return 远程组件仓库最新版本文件API.
   */
  virtual auto get_remote_service_repo_latest_version_api() const
      -> const std::string & override;
  /**
   * 是否检查远程仓库组件更新.
   *
   * \return true或者false
   */
  virtual auto is_open_remote_update() const -> bool override;
  /**
   * 获取远程仓库检查周期，秒.
   *
   * \return 远程仓库检查周期，秒.
   */
  virtual auto get_remote_repo_check_interval() const -> int override;
  /**
   * 是否启动为守护进程.
   *
   * \return true或者false
   */
  virtual auto is_start_as_daemon() const -> bool override;
  /**
   * 获取HTTP调用超时时间,秒.
   *
   * \return HTTP调用超时时间,秒.
   */
  virtual auto get_http_max_call_timeout() const -> int override;
  /**
   * 是否开启RPC信息统计.
   *
   * \return true或者false
   */
  virtual auto is_open_rpc_stat() -> bool override;
  /**
   * 是否开启链路跟踪.
   *
   * \return true或者false
   */
  virtual auto is_open_trace() -> bool override;
  /**
   * 获取模块存放路径.
   *
   * \return 模块存放路径
   */
  virtual auto get_module_dir() -> const std::string & override;
  /**
   * 获取配置的版本号
   */
  virtual auto get_version() -> const std::string & override;
  /**
   * 获取RPC超时开关
   */
  virtual auto is_open_rpc_timeout() -> bool override;
  /**
   * 检测属性是否存在.
   *
   * \param name 属性名
   * \return true或false
   */
  virtual auto has_attribute(const std::string &name) -> bool override;
  /**
   * @brief 获取listener.host网络类型
   * @return 网络类型
   */
  virtual auto get_listener_host_type() -> const std::string & override;
  virtual auto is_open_limit() -> bool override;
  virtual auto get_limit_config() -> const LimitConfigVector & override;
  virtual auto is_auto_load_service() -> bool override;

public:
  /**
   * 获取配置文件路径.
   *
   * \return 配置文件路径
   */
  auto get_config_file_path() const -> const std::string &;

  /**
   * 设置服务发现节点连接超时，毫秒.
   * \param timeout 超时, 秒
   */
  auto set_service_finder_connect_timeout(int timeout) -> void;

  /**
   * 设置连接其他服务容器超时，毫秒.
   * \param timeout 超时, 秒
   */
  auto set_connect_other_box_timeout(int timeout) -> void;

  /**
   * 设置网络读缓冲区长度,字节.
   * \param len 缓冲区长度
   */
  auto set_box_channel_recv_buffer_len(int len) -> void;

  /**
   * 设置HTTP调用/请求超时，
   * \param timeout 超时, 秒
   */
  auto set_http_max_call_timeout(int timeout) -> void;

  /**
   * 设置自动更新
   */
  auto set_is_open_remote_update(bool on_off) -> void;
  /**
   * 设置RPC统计开关
   */
  auto set_is_open_rpc_stat(bool value) -> void;
  /**
   * 设置远程更新检查周期，秒
   */
  auto set_remote_repo_check_interval(int second) -> void;
  /**
   * @brief 拷贝数据属性
   * @param rht 配置实例
   * @return
   */
  auto copy_attribute(const BoxConfigImpl &rht) -> void;
  /**
   * 获取服务名对应的服务UUID.
   *
   * \param service_name 服务名
   * \return 服务UUID
   */
  auto get_uuid_by_service_name(const std::string &service_name)
      -> const std::string &;
  /**
   * 获取限流配置
   */
  auto load_limit_config() -> bool;
  /**
   * 在配置的服务目录内查找所有可加载服务
   */
  auto find_all_services() -> void;

protected:
  auto operator=(BoxConfigImpl &&rht) noexcept -> const BoxConfigImpl &;
  /**
   * 调用配置重载监听器.
   *
   * \param config 新配置
   * \return
   */
  auto call_reload_listener(const BoxConfigImpl &config) -> void;

protected:
  /**
   * 注册配置函数.
   *
   * \return
   */
  auto register_config_function() -> void;
  /**
   * 注册配置变量.
   *
   * \return
   */
  auto register_config_variable() -> void;
  /**
   * 配置函数，获取操作系统名.
   */
  DECLARE_FUNCTION(os_name);

  /**
   * 配置函数，打印.
   */
  DECLARE_FUNCTION(print);

  /**
   * 是否是调试版本.
   *
   */
  DECLARE_FUNCTION(is_debug);

  /**
   * 是否是发行版本.
   *
   */
  DECLARE_FUNCTION(is_release);

  /**
   * 获取当前工作目录.
   *
   */
  DECLARE_FUNCTION(cwd);
  /**
   * 获取容器二进制程序路径.
   *
   */
  DECLARE_FUNCTION(bin_path);
  /**
   * 获取容器二进制程序名字.
   *
   */
  DECLARE_FUNCTION(bin_name);
  /**
   * 执行命令.
   *
   */
  DECLARE_FUNCTION(exec);
  /**
   * 执行命令.
   *
   */
  DECLARE_FUNCTION(get_env);
};

} // namespace config
} // namespace kratos
